using System;
using System.Collections.Generic;
using System.Linq;
using BCW.GameTypes.SkyBlock;
using UnityEngine;

public class SpawnPointChief : MonoBehaviour
{
	[Serializable]
	public struct SpawnPoint
	{
		public Vector3 position;

		public Quaternion rotation;
	}

	[Serializable]
	public struct SpawnPointPVP
	{
		public string nameArea;

		public List<SpawnPoint> pvpSpawn;
	}

	[HideInInspector]
	public EPointSpawn showSpawn;

	public static List<string> listNameArea = new List<string> { "pvp4_china", "pvp3_military", "pvp5_beach", "pvp6_port", "pvp7_stadium", "pvp8_hospital" };

	public static SpawnPointChief instance;

	public GameObject spawnPointSample;

	public float distanceFromTheGround = 1.5f;

	public List<SpawnPoint> redTeamSpawnPoints = new List<SpawnPoint>();

	public List<SpawnPoint> blueTeamSpawnPoints = new List<SpawnPoint>();

	public List<SpawnPoint> playerSpawnPointsNew = new List<SpawnPoint>();

	public List<SpawnPoint> playerFirstSpawnPointsNew = new List<SpawnPoint>();

	public List<SpawnPointPVP> playerFirstSpawnGameObject = new List<SpawnPointPVP>();

	private List<SpawnPoint> loadedList;

	public Dictionary<string, List<SpawnPoint>> playerFirstSpawnFromPVP = new Dictionary<string, List<SpawnPoint>>();

	private List<Vector3> lastPointForRespawn = new List<Vector3>();

	private List<SpawnPoint> disabledPoint = new List<SpawnPoint>();

	private void Awake()
	{
		instance = this;
		for (int i = 0; i < playerFirstSpawnGameObject.Count; i++)
		{
			playerFirstSpawnFromPVP.Add(playerFirstSpawnGameObject[i].nameArea, playerFirstSpawnGameObject[i].pvpSpawn);
		}
	}

	private void OnDestroy()
	{
		instance = null;
	}

	public SpawnPoint getRandomPointForTDM(PlayerBehavior player)
	{
		PunTeams.Team localTeam = player.localTeam;
		List<SpawnPoint> list = ((localTeam != PunTeams.Team.blue) ? redTeamSpawnPoints.ToList() : blueTeamSpawnPoints.ToList());
		return RandomizePoint(FindAwailableRandomPoint(list, player));
	}

	public SpawnPoint GetRandomPointForSkyBlock(PlayerBehavior player)
	{
		PunTeams.Team localTeam = player.localTeam;
		if (localTeam != 0 && SkyBlockController.instance != null)
		{
			List<SpawnPoint> list = ((localTeam != PunTeams.Team.blue) ? redTeamSpawnPoints.ToList() : blueTeamSpawnPoints.ToList());
			return FindAwailableRandomPoint(list, player);
		}
		return default(SpawnPoint);
	}

	public SpawnPoint getRandomPointForCopsNRobbers(PlayerBehavior player)
	{
		PunTeams.Team localTeam = player.localTeam;
		int num = CopsAndRobbersController.instance.gates.Count * 10;
		if (blueTeamSpawnPoints.Count != num || redTeamSpawnPoints.Count != num)
		{
			BCWDebug.LogError("LOG: точек спауна для одной команды должно быть [кол-во ворот * 10]");
		}
		int currentStage = CopsAndRobbersController.instance.GetCurrentStage();
		if (localTeam != 0)
		{
			List<SpawnPoint> source = ((localTeam != PunTeams.Team.blue) ? redTeamSpawnPoints : blueTeamSpawnPoints);
			List<SpawnPoint> list = source.Where((SpawnPoint _, int index) => index >= currentStage * 10 && index < (currentStage + 1) * 10).ToList();
			if (currentStage < 0)
			{
				list = source.Take(10).ToList();
			}
			return FindAwailableRandomPoint(list, player);
		}
		BCWDebug.LogError("LOG: пытаемся зареспаунить чувака, а его команда none");
		return default(SpawnPoint);
	}

	public SpawnPoint GetRandomPointForTitanFallV2(PlayerBehavior player)
	{
		return FindAwailableRandomPoint(playerSpawnPointsNew, player);
	}

	public SpawnPoint GetRandomPointForPixelmon(PlayerBehavior player)
	{
		PunTeams.Team localTeam = player.localTeam;
		if (localTeam != 0 && PixelmonController.instance != null)
		{
			List<SpawnPoint> list = ((localTeam != PunTeams.Team.blue) ? PixelmonController.instance.teamSpawnRed : PixelmonController.instance.teamSpawnBlue);
			return FindAwailableRandomPoint(list, player);
		}
		return default(SpawnPoint);
	}

	public void ReservPoint(SpawnPoint point)
	{
		disabledPoint.Add(point);
		CoroutineRunner.Invoke(6f, delegate
		{
			disabledPoint.Remove(point);
		});
	}

	private float Distance(float a, float b)
	{
		return Mathf.Abs(a - a);
	}

	public SpawnPoint GetPointInAreaRespawn(bool resetAreaName, PlayerBehavior player)
	{
		string text = BCWStorage.Get<string>(settings.keyNameArea);
		if (resetAreaName)
		{
			settings.SetAreaNameForRespawn(string.Empty, false);
		}
		if (settings.offlineMode)
		{
			text = listNameArea.Where((string x) => x != "pvp11_Zombie" && x != "pvp3_military").ToList().RandomElement();
			BCWStorage.Set(settings.keyNameArea, text);
			return RandomSpawnFromPVP(listNameArea.Where((string x) => x != "pvp3_military").ToList().RandomElement(), player);
		}
		if (text == string.Empty && GameController.instance.curTypeGame != 0)
		{
			return RandomSpawnFromPVP(text, player);
		}
		text = listNameArea.Where((string x) => x != "pvp11_Zombie").ToList().RandomElement();
		BCWStorage.Set(settings.keyNameArea, text);
		return RandomSpawnFromPVP(listNameArea.Where((string x) => x != "pvp11_Zombie").ToList().RandomElement(), player);
	}

	public SpawnPoint getRandomPointNearPlayer(PlayerBehavior player)
	{
		if (TutorialManager.TuturialWorking())
		{
			return TutorialManager.instance.GetSpawnPoint();
		}
		if (GameController.instance.myPlayer == null && GameController.instance.curTypeGame != 0)
		{
			return GetRandomPointFirstSpawn(player);
		}
		if (ParametersLevel.instance.currentMapType == mapType.Global)
		{
			List<SpawnPoint> list = instance.playerSpawnPointsNew.ToList();
			list.RemoveAll(delegate(SpawnPoint x)
			{
				float num = Vector3.Distance(player.transform.position, x.position);
				return num < 50f || num > 150f;
			});
			if (list.Count == 0)
			{
				SpawnPoint pointInAreaRespawn = GetPointInAreaRespawn(true, player);
				if (pointInAreaRespawn.position != Vector3.zero)
				{
					lastPointForRespawn.Add(pointInAreaRespawn.position);
					return pointInAreaRespawn;
				}
			}
			return RandomizePoint(FindAwailableRandomPoint(list, player));
		}
		return getRandomPointAllMap(player);
	}

	public SpawnPoint GetRandomPointFirstSpawn(PlayerBehavior myPlayer)
	{
		List<SpawnPoint> list = instance.playerFirstSpawnPointsNew.ToList();
		return RandomizePoint(FindAwailableRandomPoint(list, myPlayer));
	}

	public SpawnPoint getRandomPointAllMap(PlayerBehavior mMyPlayer)
	{
		List<SpawnPoint> list = instance.playerSpawnPointsNew.ToList();
		return RandomizePoint(FindAwailableRandomPoint(list, mMyPlayer));
	}

	public static SpawnPoint RandomizePoint(SpawnPoint basePoint)
	{
		basePoint.position += Vector3.up * 0.1f;
		SpawnPoint spawnPoint = basePoint;
		bool flag = false;
		int num = 0;
		Vector3 vector = Vector3.up * 2f;
		float num2 = 1.5f;
		for (float num3 = num2; num3 > 1f; num3 -= 1f)
		{
			flag = false;
			num = 0;
			bool flag2 = true;
			while (!flag && num++ < 15)
			{
				spawnPoint.position.x = basePoint.position.x + UnityEngine.Random.Range(0f - (num3 - 1f), num3);
				spawnPoint.position.z = basePoint.position.z + UnityEngine.Random.Range(0f - (num3 - 1f), num3);
				RaycastHit hitInfo;
				Physics.Linecast(basePoint.position + Vector3.up, spawnPoint.position + Vector3.up, out hitInfo);
				flag = hitInfo.collider == null || (hitInfo.collider != null && hitInfo.collider.GetComponentInParent<Mortal>() != null);
				if (flag && Physics.Raycast(spawnPoint.position + vector, Vector3.down, out hitInfo, 2f))
				{
					spawnPoint.position = hitInfo.point + Vector3.up * 0.1f;
				}
			}
			if (flag && flag2)
			{
				BCWDebug.Log(string.Format("Base point = {0}, Spawn point = {1}, Difference is {2}", basePoint.position, spawnPoint.position, Vector3.Distance(basePoint.position, spawnPoint.position)));
				basePoint.position = spawnPoint.position;
				break;
			}
		}
		return basePoint;
	}

	private SpawnPoint RandomSpawnFromPVP(string key, PlayerBehavior player)
	{
		List<SpawnPoint> value;
		if (!playerFirstSpawnFromPVP.TryGetValue(key, out value) || value.Count == 0)
		{
			value = instance.playerSpawnPointsNew;
		}
		return RandomizePoint(FindAwailableRandomPoint(value, player));
	}

	public SpawnPoint FindAwailableRandomPoint(List<SpawnPoint> list, PlayerBehavior player)
	{
		int count = list.Count;
		System.Random random = new System.Random();
		list = list.OrderBy((SpawnPoint _) => random.Next()).ToList();
		List<SpawnPoint> list2 = list.ToList();
		list.RemoveAll(delegate(SpawnPoint x)
		{
			for (int j = 0; j < disabledPoint.Count; j++)
			{
				if (Mathf.Abs(disabledPoint[j].position.x - x.position.x) < 2f && Mathf.Abs(disabledPoint[j].position.y - x.position.y) < 2f)
				{
					BCWDebug.Log("Нашли зарерервированную точку. Ищем дельше....");
					return true;
				}
			}
			return false;
		});
		if (list.Count == 0)
		{
			list = list2;
		}
		for (int i = 0; i < list.Count; i++)
		{
			Collider[] source = Physics.OverlapSphere(list[i].position + Vector3.up * 1.5f, 3f);
			if (!source.Any(delegate(Collider x)
			{
				Mortal componentInParent = x.gameObject.GetComponentInParent<Mortal>();
				return componentInParent != null && componentInParent != player && componentInParent != player.currentCar;
			}))
			{
				ReservPoint(list[i]);
				return list[i];
			}
		}
		if (list.Count == 0)
		{
			return default(SpawnPoint);
		}
		SpawnPoint spawnPoint = list.RandomElement();
		ReservPoint(spawnPoint);
		return spawnPoint;
	}

	public void GeneratePoints(List<SpawnPoint> points)
	{
		DeletePoints();
		foreach (SpawnPoint point in points)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(spawnPointSample);
			gameObject.transform.parent = base.transform;
			gameObject.transform.position = point.position;
			gameObject.transform.rotation = point.rotation;
		}
		loadedList = points;
	}

	public void DeletePoints()
	{
		List<Transform> list = base.transform.Cast<Transform>().ToList();
		foreach (Transform item in list)
		{
			UnityEngine.Object.DestroyImmediate(item.gameObject);
		}
		loadedList = null;
	}

	public void AcceptNewPositions()
	{
		foreach (Transform item in base.transform)
		{
			if (item.tag.Equals("SpawnPoint"))
			{
				loadedList.Add(new SpawnPoint
				{
					position = item.position,
					rotation = item.rotation
				});
			}
		}
		GeneratePoints(loadedList);
	}

	public void SavePoints(List<SpawnPoint> points)
	{
		points.Clear();
		foreach (Transform item in base.transform)
		{
			if (item.tag.Equals("SpawnPoint"))
			{
				points.Add(new SpawnPoint
				{
					position = item.position,
					rotation = item.rotation
				});
			}
		}
	}

	public void ClearList(List<SpawnPoint> points)
	{
		points.Clear();
	}
}
